using UnityEngine;
using GameBaseFramework.Attribute;
using System.Collections.Generic;
using System;
using UnityEditor;
using GameBaseFramework.Base;
using GameLogic.AbilitySystem.Effect;
using System.Linq;
using GameBaseFramework.Extension;
using Unity.VisualScripting;
using UnityEngine.Events;

namespace GameLogic.AbilitySystem.Attribute
{
    /// <summary>
    /// 属性枚举
    /// </summary>
    [Serializable]
    public enum AttributeType
    {
        Health,
        MaxHealth,
        Mana,
        MaxMana,
        Attack,
        Defense,
        Damage, 
        MoveSpeed,
        TurnSpeed,
    }

    /// <summary>
    /// 作用在具体哪种属性上
    /// </summary>
    [Serializable]
    public enum TargetAttributeType
    {
        Base,
        Current
    }

    /// <summary>
    /// 具体是加/减/乘/除或是直接Set
    /// </summary>
    [Serializable]
    public enum AttributeOperator
    {
        Set,
        Add,
        Mul,
    }

    /// <summary>
    /// 数值改变器
    /// </summary>

    [Serializable]
    public class AttributeModifier
    {
        /// <summary>
        /// 作用属性
        /// </summary>
        public AttributeType type;

        /// <summary>
        /// 作用在Base/Current上
        /// </summary>
        public TargetAttributeType targetType;

        /// <summary>
        /// 符号
        /// </summary>
        public AttributeOperator Operator;

        /// <summary>
        /// 具体改变多少
        /// </summary>
        public float ModifyValue;

        /// <summary>
        /// 构造
        /// </summary>
        public AttributeModifier(AttributeType _type = 0,
            TargetAttributeType _target = TargetAttributeType.Base,
            AttributeOperator _operator = AttributeOperator.Set,
            float _modifyValue = 0f)
        {
            type = _type;
            targetType = _target;
            Operator = _operator;
            ModifyValue = _modifyValue;
        }

        public AttributeModifier()
        {
            type = 0;
            targetType = TargetAttributeType.Base;
            Operator = AttributeOperator.Set;
            ModifyValue = 0f;
        }
    }

    /// <summary>
    /// Buff改变器，改变BaseValue和CurrentValue之间的作用值
    /// 直接覆盖，算好不同buff之间的重叠效果之后再传入
    /// </summary>
    [Serializable]
    public class LinearFunctionModifier
    {
        /// <summary>
        /// 作用属性
        /// </summary>
        public AttributeType type;


        /// <summary>
        /// buff
        /// </summary>
        public LinearFunction function;

        public LinearFunctionModifier(AttributeType _type = (AttributeType)0, LinearFunction _function = null)
        {
            type = _type;
            function = _function;
        }
    }

    /// <summary>
    /// 基础数值集
    /// 添加一个新数值的流程
    /// </summary>
    [Serializable]
    public class AttributeSet : ScriptableObject
    {
        /// <summary>
        /// 标签集合
        /// </summary>
        public HashSet<string> Tags;

        /// <summary>
        /// 有标签
        /// </summary>
        /// <param name="tag"></param>
        /// <returns></returns>
        public bool ContainsTag(string tag)
        {
            return Tags.Contains(tag);
        }

        /// <summary>
        /// 构造
        /// </summary>
        public AttributeSet()
        {
            Init();
        }

        /// <summary>
        /// 序列化的字典
        /// </summary>
        public List<FloatAttribute> Attributes = new();

        /// <summary>
        /// 获得对应的属性
        /// </summary>
        /// <param name="attributeType"></param>
        /// <returns></returns>
        public FloatAttribute GetAttribute(AttributeType attributeType)
        {
            return Attributes[(int)attributeType];
        }

        /// <summary>
        /// 初始化
        /// </summary>
        public void Init()
        {
            Attributes = new();
            foreach (var i in Enum.GetValues(typeof(AttributeType)))
            {
                Attributes.Add(new FloatAttribute());
            }
        }

        /// <summary>
        /// 修改
        /// </summary>
        public void Modify(AttributeType type, AttributeModifier modifier)
        {
            var value = modifier.ModifyValue;
            float newCurrent;
            float newBase;
            switch (modifier.Operator)
            {
                case AttributeOperator.Set:
                    if (modifier.targetType == TargetAttributeType.Base)
                    {
                        newBase = GetAttribute(type).BaseValue;
                        newCurrent = GetAttribute(type).ValueFunction.slope * newBase +
                                     GetAttribute(type).ValueFunction.intercept;
                    }
                    else
                    {
                        newCurrent = GetAttribute(type).CurrentValue;
                        newBase = newCurrent / GetAttribute(type).ValueFunction.slope -
                                  GetAttribute(type).ValueFunction.intercept;
                    }
                    break;
                case AttributeOperator.Add:
                    if (modifier.targetType == TargetAttributeType.Base)
                    {
                        newBase = GetAttribute(type).BaseValue + value;
                        newCurrent = GetAttribute(type).ValueFunction.slope * newBase +
                                     GetAttribute(type).ValueFunction.intercept;
                    }
                    else
                    {
                        newCurrent = GetAttribute(type).CurrentValue + value;
                        newBase = newCurrent / GetAttribute(type).ValueFunction.slope -
                                  GetAttribute(type).ValueFunction.intercept;
                    }
                    break;
                case AttributeOperator.Mul:
                    if (modifier.targetType == TargetAttributeType.Base)
                    {
                        newBase = GetAttribute(type).BaseValue * value;
                        newCurrent = GetAttribute(type).ValueFunction.slope * newBase +
                                     GetAttribute(type).ValueFunction.intercept;
                    }
                    else
                    {
                        newCurrent = GetAttribute(type).CurrentValue * value;
                        newBase = newCurrent / GetAttribute(type).ValueFunction.slope -
                                  GetAttribute(type).ValueFunction.intercept;
                    }
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }

            PreModify(type, ref newBase, ref newCurrent);
            if (modifier.targetType == TargetAttributeType.Base)
            {
                GetAttribute(type).BaseValue = newBase;
            }
            else
            {
                GetAttribute(type).CurrentValue = newCurrent;
            }
            PostModify(type, GetAttribute(type));
        }

        /// <summary>
        /// 批量修改
        /// </summary>
        /// <param name="modifyValues"></param>
        public void Modify(List<AttributeModifier> modifyValues)
        {
            foreach (var i in modifyValues)
            {
                Modify(i.type, i);
            }
        }

        /// <summary>
        /// 修改Buff
        /// </summary>
        /// <param name="type"></param>
        /// <param name="function"></param>
        public void ModifyBuff(AttributeType type, LinearFunctionModifier modifier)
        {
            var function = modifier.function;

            float newBase = GetAttribute(type).BaseValue;
            float newCurrent = GetAttribute(type).ValueFunction.intercept +
                               GetAttribute(type).ValueFunction.slope * newBase;
            PreModify(type, ref newBase, ref newCurrent);
            GetAttribute(type).ValueFunction = function;
            GetAttribute(type).BaseValue = GetAttribute(type).BaseValue;
            PostModify(type, GetAttribute(type));
        }

        /// <summary>
        /// 修改Buff
        /// </summary>
        /// <param name="modifyFunctions"></param>
        public void ModifyBuff(List<LinearFunctionModifier> modifyFunctions)
        {
            foreach (var i in modifyFunctions)
            {
                ModifyBuff(i.type, i);
            }
        }

        /// <summary>
        /// 数值变化之前，提供一个修改数值的机会
        /// </summary>
        /// <param name="type"></param>
        /// <param name="BaseValue"></param>
        /// <param name="CurrentValue"></param>
        protected virtual void PreModify(AttributeType type, ref float BaseValue, ref float CurrentValue)
        {

        }


        /// <summary>
        /// 数值变化之后，允许修改数值
        /// </summary>
        /// <param name="type"></param>
        /// <param name="BaseValue"></param>
        /// <param name="CurrentValue"></param>
        protected virtual void PostModify(AttributeType type, FloatAttribute attribute)
        {

        }

        /// <summary>
        /// 重载比较符
        /// </summary>
        /// <param name="self"></param>
        /// <param name="other"></param>
        /// <returns></returns>
        public static bool operator<=(AttributeSet self, AttributeSet other)
        {
            foreach (var i in Enum.GetValues(typeof(AttributeType)))
            {
                var attribute = (AttributeType)i;
                if (self.GetAttribute(attribute).CurrentValue > other.GetAttribute(attribute).CurrentValue) return false;
            }

            return true;
        }

        /// <summary>
        /// 重载比较符
        /// </summary>
        /// <param name="self"></param>
        /// <param name="other"></param>
        /// <returns></returns>
        public static bool operator >=(AttributeSet self, AttributeSet other)
        {
            foreach (var i in Enum.GetValues(typeof(AttributeType)))
            {
                var attribute = (AttributeType)i;
                if (self.GetAttribute(attribute).CurrentValue < other.GetAttribute(attribute).CurrentValue) return false;
            }
            return true;
        }

        public static AttributeSet operator +(AttributeSet self, AttributeSet other)
        {
            foreach (var i in Enum.GetValues(typeof(AttributeType)))
            {
                var attribute = (AttributeType)i;
                self.GetAttribute(attribute).CurrentValue += other.GetAttribute(attribute).CurrentValue;
            }
            return self;
        }

        public static AttributeSet operator -(AttributeSet self, AttributeSet other)
        {
            foreach (var i in Enum.GetValues(typeof(AttributeType)))
            {
                var attribute = (AttributeType)i;
                self.GetAttribute(attribute).CurrentValue += other.GetAttribute(attribute).CurrentValue;
            }
            return self;
        }

        public static AttributeSet operator *(AttributeSet self, float mul)
        {
            foreach (var i in Enum.GetValues(typeof(AttributeType)))
            {
                var attribute = (AttributeType)i;
                self.GetAttribute(attribute).CurrentValue *= mul;
            }
            return self;
        }

        public static AttributeSet operator /(AttributeSet self, float mul)
        {
            if (mul == 0) return self;
            foreach (var i in Enum.GetValues(typeof(AttributeType)))
            {
                var attribute = (AttributeType)i;
                self.GetAttribute(attribute).CurrentValue /= mul;
            }
            return self;
        }




    }
}
